package swing.admin.dao;


import swing.admin.utils.JdbcUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class BaseMapper<T> {


    private Class<T> clazz;

    public BaseMapper(Class<T> clazz) {
        this.clazz = clazz;
    }

    private boolean execute(String sql, Object... params) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = JdbcUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            if (params != null) {
                buildParams(preparedStatement, params);
            }
            return preparedStatement.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(connection, preparedStatement, null);
        }
        return false;
    }

    public boolean insert(String sql, Object... params) {
        return execute(sql, params);
    }

    public boolean delete(String sql, Object... params) {
        return execute(sql, params);
    }

    public int update(String sql, Object... params) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = JdbcUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            if (params != null) {
                buildParams(preparedStatement, params);
            }
            return preparedStatement.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(connection, preparedStatement, null);
        }
        return 0;
    }


    public T selectOne(String sql, Object... params) {
        List<T> list = selectList(sql, params);
        if (list.size() == 0) {
            return null;
        }
        return (T) list.get(0);
    }

    public List<T> selectList(String sql, Object... params) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<T> list = new ArrayList<T>();

        try {
            connection = JdbcUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            if (params != null) {
                buildParams(preparedStatement, params);
            }
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                list.add(buildObject(resultSet));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(connection, preparedStatement, resultSet);
        }
        return list;
    }

    private T buildObject(ResultSet resultSet) throws Exception {
        T object = clazz.newInstance();
        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
        for (int i = 0; i < resultSetMetaData.getColumnCount(); i++) {
            String colName = resultSetMetaData.getColumnName(i + 1);
            PropertyDescriptor propertyDescriptor;
            if (colName.contains("_")) {
                // 解决 Exception in thread "main" java.beans.IntrospectionException: Method not found: isMajor_id
                propertyDescriptor = new PropertyDescriptor(toCamelCase(colName), clazz);
            } else {

                propertyDescriptor = new PropertyDescriptor(colName, clazz);
            }
            Method method = propertyDescriptor.getWriteMethod();
            method.invoke(object, resultSet.getObject(colName));
        }
        return object;
    }

    private static String toCamelCase(String s) {
        if (s == null || s.isEmpty()) {
            return s;
        }

        s = s.toLowerCase();

        StringBuilder sb = new StringBuilder();
        boolean upperCase = false;

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);

            if (c == '_') {
                upperCase = true;
            } else if (upperCase) {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            } else {
                sb.append(c);
            }
        }

        return sb.toString();
    }

    private void buildParams(PreparedStatement preparedStatement, Object... params) throws SQLException {
        for (int i = 0; i < params.length; i++) {
            preparedStatement.setObject(i + 1, params[i]);
        }
    }

}
